package com.black.gateway.auth.service.impl;

import com.black.gateway.auth.vo.AuthToken;
import com.black.gateway.auth.service.AuthService;
import com.black.gateway.exception.OauthException;
import io.micrometer.core.lang.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URI;
import java.util.Map;

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AuthServiceImpl implements AuthService {

    @Value("${share.auth.clientSecret}")
    private String clientSecret;
    @Value("${share.auth.serviceName}")
    private String authServiceName;

    @Value("${wx.clientId}")
    private String weChatClientId;
    @Value("${wx.clientSecret}")
    private String wechatClientSecret;

    private final LoadBalancerClient loadBalancerClient;

    private final RestTemplate restTemplate;


    @Override
    public AuthToken login(String username, String password) {
        return applyToken(username, password, null, weChatClientId, wechatClientSecret);
    }

    @Override
    public AuthToken getUserToken(String code, String clientId) {
        return applyToken(null, null, code, clientId, clientSecret);
    }

    @SuppressWarnings("all")
    private AuthToken applyToken(String username, String password, String code, String clientId, String clientSecret) {
        //从nacos中获取认证服务的地址（因为spring security在认证服务中）
        ServiceInstance serviceInstance = loadBalancerClient.choose(authServiceName);
        //此地址就是http://ip:port
        URI uri = serviceInstance.getUri();
        String authUrl = uri + "/oauth/token";
        //定义header
        LinkedMultiValueMap<String, String> header = new LinkedMultiValueMap<>();
        //定义body
        LinkedMultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        if (StringUtils.isEmpty(code)) {
            //String httpBasic = getHttpBasic(clientId, clientSecret);
            //header.add("Authorization", httpBasic);
            body.add("grant_type", "password");
            body.add("username", username);
            body.add("password", password);
            body.add("client_id", clientId);
            body.add("client_secret", clientSecret);
        } else {
            body.add("grant_type", "authorization_code");
            body.add("code", code);
            body.add("client_id", clientId);
            body.add("client_secret", clientSecret);
        }
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, header);
        //设置restTemplate远程调用时候，对400和401不让报错，正确返回数据
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            public void handleError(@NonNull ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) {
                    super.handleError(response);
                }
            }
        });

        ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);
        //申请令牌信息
        return getAuthToken(exchange.getBody());
    }

    //获取httpbasic的串
    private String getHttpBasic(String clientId, String clientSecret) {
        String string = clientId + ":" + clientSecret;
        //将串进行base64编码
        byte[] encode = Base64Utils.encode(string.getBytes());
        return "Basic " + new String(encode);
    }

    @SuppressWarnings("all")
    private AuthToken getAuthToken(Map bodyMap) {
        if (bodyMap == null ||
                bodyMap.get("access_token") == null ||
                bodyMap.get("jti") == null) {
            //解析spring security返回的错误信息
            if (bodyMap != null && bodyMap.get("error_description") != null) {
                String errorDescription = (String) bodyMap.get("error_description");
                throw new OauthException(errorDescription, 401);
            }
            return null;
        }
        AuthToken authToken = new AuthToken();
        //用户身份令牌
        authToken.setAccess_token((String) bodyMap.get("jti"));
        //刷新令牌
        if (bodyMap.get("refresh_token")!=null){
            authToken.setRefresh_token((String) bodyMap.get("refresh_token"));
        }
        //jwt令牌
        authToken.setJwt_token((String) bodyMap.get("access_token"));
        return authToken;
    }
}
